/**
 * Description: 使用IIC协议从加速度传感器获取数据 
 * File: iic.c |Time: 2021-05-19 22:09
 */
#include "iic.h"
#include "gpio.h"

void delay_us()
{
    int i;
    int j;
    for (i = 0; i < 1; i++) 
    {
        for (j = 0; j < 1400; j++);
    }
}

void iic_init(void)
{
    hal_gpio_init(GPIOD, GPIO_PIN_6, ALT0);
    hal_gpio_init(GPIOD, GPIO_PIN_7, ALT0);
    hal_gpio_mode(GPIOD, GPIO_PIN_6, OUT_MODE);
    hal_gpio_mode(GPIOD, GPIO_PIN_7, OUT_MODE);
    hal_gpio_write(GPIOD, GPIO_PIN_6, HIGH_LEVEL);
    hal_gpio_write(GPIOD, GPIO_PIN_7, HIGH_LEVEL);
    delay_us();
}

// 发送起始信号
void iic_start()
{
    SDA_MODE_OUT;
    SDA_HIGH;
    SCL_HIGH;
    delay_us();
    // 时钟总线高电平期间数据线拉低为起始信号
    SDA_LOW;
    delay_us();
}


// 发送终止信号
void iic_stop()
{
    SDA_MODE_OUT;
    SCL_LOW;
    SDA_LOW;
    delay_us();
    SCL_HIGH;
    delay_us();
    // 时钟总线高电平期间数据线拉高为终止信号
    SDA_HIGH;
    delay_us();
}

// 发送ack信号
void iic_ack(ack_t ack)
{
    SDA_MODE_OUT;
    SCL_LOW;
    delay_us();

    if (ack == ACK) 
    {
        SDA_LOW;
    } else {
        SDA_HIGH;
    }

    delay_us();
    SCL_HIGH;
    delay_us();
    /*SCL_LOW;
    delay_us();
    */
}

// 发送寻址信号
// 数据发送先发送高位再发送低位
void iic_dev_addr(char dev_addr, trans_t trans)
{
    // 地址占7位, 传送方向占1位
    dev_addr = dev_addr << 1;
    dev_addr = dev_addr | trans;

    iic_send_byte(dev_addr);
}

// 发送一个字节的数据
ack_t iic_send_byte(char byte)
{
    SDA_MODE_OUT;

    int i;
    for (i = 0; i < 8; i++) 
    {
        SCL_LOW;
        delay_us();

        if (byte & (0x1 << 7)) 
        {
            SDA_HIGH;
        }
        else
        {
            SDA_LOW;
        }

        byte = byte << 1;

        delay_us();
        SCL_HIGH;
        // 等待从机读取数据
        delay_us();
    }

    /** 等待接收ACK信号 **/
    // 时钟总线拉低，用来复位数据总线
    SCL_LOW;
    delay_us();
    // 复位数据总线
    SDA_HIGH;
    // 设置数据总线为输入模式
    SDA_MODE_IN;
    delay_us();
    // 时钟总线拉高复位
    SCL_HIGH;
    // 此时接收器向总线写入ACK消息
    delay_us();

    ack_t ack;
    if (SDA_READ) 
    {
        ack = NO_ACK;
    } else {
        ack = ACK;
    }
    SCL_LOW;

    return ack;
}

// 读取一个字节
char iic_read_byte(ack_t ack)
{
    SDA_MODE_IN;
    unsigned char recv_byte = 0;
    int i;

    for (i = 0; i < 8; i++) 
    {
        SCL_LOW;
        delay_us();
        SCL_HIGH;
        delay_us();

        recv_byte = recv_byte << 1;

        if (SDA_READ == HIGH_LEVEL) 
        {
            recv_byte |= 0x1;
        }
        else
        {
            recv_byte |= 0x0;
        }

        delay_us();
    }

    iic_ack(ack);

    return recv_byte;
}

// 从加速度传感器读取数据
char mma8451_read_byte(char reg_addr)
{
    iic_start();
    iic_dev_addr(SLAVE_ADDR, HOST_TRANS);
    iic_send_byte(reg_addr);
    iic_start();
    iic_dev_addr(SLAVE_ADDR, HOST_RECV);
    char read_res = iic_read_byte(NO_ACK);
    iic_stop();
    return read_res;
}

// 向加速度传感器发送数据
void mma8451_write_tyte(char reg_addr, char data)
{
    iic_start();
    iic_dev_addr(SLAVE_ADDR, HOST_TRANS);
    iic_send_byte(reg_addr);
    iic_send_byte(data);
    iic_stop();
}

// 加速度传感器初始化
void mma8451_init()
{
    iic_init();
    mma8451_write_tyte(0x0E, 0x0); // 量程 +- 2g
    mma8451_write_tyte(0x2A, 0x1); // 激活态
    mma8451_write_tyte(0x2B, 0x2); // 高分辨率
}

// 从加速度传感器获取xyz三轴加速度
short get_xyz_from_mma8451(char reg_base_addr)
{
    char msb;
    char lsb;
    short res = 0;
    msb = mma8451_read_byte(reg_base_addr);
    lsb = mma8451_read_byte(reg_base_addr + 1);
    res = msb;
    res = (res << 8) | lsb;

    return res >> 2;
}




